# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

import os
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
import base64


import time
import random


def aes_encrypt(content, key):
    return aes_cbc_encrypt(content, key)


def aes_cbc_encrypt(message, key):

    # ENCRY_ALGORITHM = "AES"
    # CIPHER_MODE = "AES/ECB/PKCS5Padding";
    '''
    use AES CBC to encrypt message, using key and init vector
    :param message: the message to encrypt
    :param key: the secret
    :return: bytes init_vector + encrypted_content
    '''
    # iv_len = 16
    assert type(message) in (str, bytes)
    assert type(key) in (str, bytes)

    print(message, key)

    if type(message) == str:
        message = bytes(message, 'utf-8')
    if type(key) == str:
        key = bytes(key, 'utf-8')

    print(message, key)

    backend = default_backend()
    # iv = os.urandom(iv_len)

    cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=backend)
    encryptor = cipher.encryptor()

    padder = padding.PKCS7(128).padder()
    padded_data = padder.update(message) + padder.finalize()

    enc_content = encryptor.update(padded_data) + encryptor.finalize()

    # enc_content = encryptor.update(message) + encryptor.finalize()

    # modhex_encode(enc_content)

    # print('iv', iv)
    print('enc_content', enc_content)

    ll = len(enc_content)
    print('enc_content', ll)

    aa = [(one // 16,  one - ((one // 16) * 16)) for one in enc_content]
    print(aa)

    # for index, one in enumerate(enc_content):
    #     print(index, one)

    return enc_content


def aes_cbc_decrypt(content, key):
    '''
    use AES CBC to decrypt message, using key
    :param content: the encrypted content using the above protocol
    :param key: the secret
    :return: decrypted bytes
    '''
    assert type(content) == bytes
    assert type(key) in (bytes, str)
    if type(key) == str:
        key = bytes(key, 'utf-8')
    iv_len = 16
    assert len(content) >= (iv_len + 16)
    iv = content[:iv_len]
    enc_content = content[iv_len:]
    backend = default_backend()
    cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
    unpadder = padding.PKCS7(128).unpadder()
    decryptor = cipher.decryptor()
    dec_content = decryptor.update(enc_content) + decryptor.finalize()
    real_content = unpadder.update(dec_content) + unpadder.finalize()
    return real_content


def get_random_key_readable(key_size=256):
    '''
    get random key for symmetric encryption
    with key_size bits
    :param key_size: bit length of the key
    :return: bytes key
    '''
    # length for urandom
    ulen = int(key_size/8/4*3)
    key = base64.b64encode(os.urandom(ulen))
    return key


def test_aes_enc_dec():
    # key = get_random_key_readable()
    key = 'OrUPI3VOgAvLtyxA'
    print('start test_aes_enc_dec,key', key)
    total_len = 0
    s = time.time()
    for i in range(1):
        mlen = random.randint(1, 1024*1024)
        total_len += mlen
        # message = os.urandom(mlen)

        message = '0!037002200105!05548062!5600.00'

        message = '01!037002200105!05548062!5600.00'

        print('start test_aes_enc_dec,message', message)

        enc = aes_cbc_encrypt(message, key)

        # 01bb6228f807b2790ce3285f5c9e5530ad07a20f471d0a3e66ddee0f48cd68736773e38cde49aeeac5f560d15fd980fe

        print('start test_aes_enc_dec,enc', enc)

        # dec = aes_cbc_decrypt(enc, key)
        # print('start test_aes_enc_dec,dec', dec)

    e = time.time()

    print('total_len', total_len)
    print('total_time', e - s)
    # print('speed', total_len / (e - s))


def rsa_encrypt(data, pub_key):
    def block_encrypt(block, pub_key):
        return

    MAX_ENCRYPT_BLOCK = 117

    # data 需要是 utf-8 格式
    inputLen = len(data)

    offset = 0
    index = 0

    out = []  # 目标

    while(inputLen - offset > 0):
        if inputLen - offset > MAX_ENCRYPT_BLOCK:
            last_point = MAX_ENCRYPT_BLOCK
        else:
            last_point = inputLen - offset

        # 取一个 block 加密
        block = data[offset:last_point]
        block2 = block_encrypt(block, pub_key)

        out = out + block2  # 加密后的内容 写入 out
        index = index+1
        offset = index * MAX_ENCRYPT_BLOCK

    encryptedData = out  # 完整的加密串 bytes.

    base64_str = base64.encodestring(encryptedData)  # 转 base64

    return base64_str
